#include "LongReadsSet.h"
CLongReadsSet::CLongReadsSet(void)
{
}

CLongReadsSet::CLongReadsSet(const char* InputFile, const char* fileFormat,\
                             unsigned int expReadStrLineLength, unsigned int allowedNumOfNinRead,\
                             unsigned int readStartIndex)
// : CPairedReadsSet(InputFile, fileFormat, expReadStrLineLength, false, allowedNumOfNinRead, readStartIndex)
{
    // this->longReadLength = expReadStrLineLength;// call parent constructor to open a file for reading long reads with  bool in5to3cat3to5Format = false;
    this->init(InputFile, fileFormat, expReadStrLineLength, false,	allowedNumOfNinRead, readStartIndex);
}

CLongReadsSet::~CLongReadsSet(void)
{
}

void CLongReadsSet::setBadReadOutputFile(FileOutputBuffer* pOut)
{
    this->parser.pOBuf = pOut;
}

unsigned int CLongReadsSet::get_next_capacity_reads(int capacity, char sep)
{
    // TODO: make use of int capacity, char sep
    bool bGetQScores = this->bGetQScores() && this->bStoreQS();
    bool bSOLiDReadFormat = this->isSOLiDReadFormat();

    this->clearReads(capacity);
    do {
        const char* caNextRead = parser.get_Next_Read(); // get next read and store in this->parser.caNextRead
        if (caNextRead[0] == '\0') {
            this->flushParser();
            break; // End of the file
        }
        bool bIsGoodRead = this->save_next_long_read(bSOLiDReadFormat, bGetQScores, this->in5to3cat3to5Format);
        if (!bIsGoodRead) {
            this->parser.print_Next_Read(); // Warning!! save_next_long_read will save read length. It should be expected length
            this->handleBadRead();
        }
    } while (this->size() < this->capacity());
    printf("Deal read no. %u in %s.\r", this->uiNo_of_Reads, this->InputFile);
    this->removeExtraTags();
    if(this->bStoreQS()) {
        this->getQualityScoresFromQUAL();
    }
    return((unsigned int)this->size());
}

void CLongReadsSet::init(const char* InputFile, const char* fileFormat,\
                         unsigned int expReadStrLineLength, bool in5to3cat3to5Format, unsigned int allowedNumOfNinRead, unsigned int readStartIndex)
{
    CPairedReadsSet::init(InputFile, fileFormat, expReadStrLineLength, in5to3cat3to5Format, allowedNumOfNinRead, readStartIndex);
    this->longReadLength = expReadStrLineLength;
}

// The private function store next read in the parser object. It returns false if the read is bad.
// For reads longer than 64 and shorter than 128, reads are store as two parts in two CReadInBits
// For odd read length, the two parts are overlapped with one base.
bool CLongReadsSet::save_next_long_read(bool bSOLiDReadFormat, bool getQScores,\
                                        bool in5to3cat3to5Format)
{
    // bool bDiscardReadWithN = this->F_Reads->bDiscardReadWithN && this->R_Reads->bDiscardReadWithN;
    /*
    char* readSeq = this->parser.caNextRead;
    unsigned int fullReadLength = (unsigned int)strlen(readSeq);
    unsigned int expFullReadLength = this->getExpReadLength(fullReadLength);
    if(fullReadLength != expFullReadLength) {
    	// TODO: Consider to fill the read if it is shorter than expected
    }
    */
    // TODO: Must allow certain number of 'N' or strange nucleotide
    if(isBadRead(bSOLiDReadFormat, this->parser.caNextRead, this->getReadLength())) {
        return(false);
    } else {
        if(bSOLiDReadFormat) {
            save_next_long_SOLiD_read(this->getReadLength(), getQScores);
        } else {
            save_next_long_Illumina_read(this->getReadLength(), getQScores, in5to3cat3to5Format);
        }
        this->save_next_read_id(this->parser.caNextReadTag);
        this->uiNo_of_Reads++; // this->uiNo_of_Reads does not include bad read.
        return(true);
    }
}

void CLongReadsSet::save_next_long_Illumina_read(unsigned int fullReadLength, bool getQScores, bool in5to3cat3to5Format)
{
    const bool bSOLiDReadFormat = false;
    char* readSeq = this->parser.caNextRead;
    char* readQS  = this->parser.caNextReadQSs;
    unsigned int eachPartLength = this->getHalfReadLength();
    unsigned int secondPartStart = fullReadLength - eachPartLength;
    if (in5to3cat3to5Format) {
        reverseKmer(&readSeq[secondPartStart]);
        if (getQScores) {
            reverseKmer(&readQS[secondPartStart]);
        }
    }
    const char* rReadSeq = &readSeq[secondPartStart];
    this->R_Reads->save_next_read(rReadSeq, bSOLiDReadFormat);
    this->parser.caNextRead[eachPartLength] = '\0';
    this->F_Reads->save_next_read(readSeq, bSOLiDReadFormat);
    if (getQScores) {
        const char* rReadQS = &readQS[secondPartStart];
        this->R_Reads->pQualScores->addQSs(rReadQS);
        readQS[eachPartLength] = '\0';
        this->F_Reads->pQualScores->addQSs(readQS);
    }
}

// The first base and the following color signals are saved into two parts
void CLongReadsSet::save_next_long_SOLiD_read(unsigned int fullReadLength, bool getQScores)
{
    const bool bSOLiDReadFormat = true;
    char* readSeq = this->parser.caNextRead;
    char* readQS  = this->parser.caNextReadQSs;
    unsigned int bufferLength = fullReadLength + 1; // Lead by a ACGT primer not belongs to the reference
    // A CReadInBitsSet encodes eachPartLength of color signal or ACGT
    unsigned int eachPartLength = this->getHalfReadLength();
    unsigned int secondPartStart = bufferLength - eachPartLength;
    const char* rReadSeq = &readSeq[secondPartStart];
    // save the 2nd part pure 0123 signal
    this->R_Reads->save_next_colorStr_as_a_read(rReadSeq);
    this->parser.caNextRead[eachPartLength + 1] = '\0';
    // save the 1st part 1-ACGT, rest 0123 signals
    this->F_Reads->save_next_read(readSeq, bSOLiDReadFormat);
    if (getQScores) {
        const char* rReadQS = &readQS[secondPartStart];
        this->R_Reads->pQualScores->addQSs(rReadQS);
        readQS[eachPartLength] = '\0';
        this->F_Reads->pQualScores->addQSs(readQS);
    }
}

const char* CLongReadsSet::get_Next_Read(void)
{
    return(this->parser.get_Next_Read());
}

bool CLongReadsSet::save_next_read(bool bSOLiDReadFormat,  bool bGetQScores)
{
    bool in5to3cat3to5Format = false;
    return(save_next_long_read(bSOLiDReadFormat, bGetQScores, in5to3cat3to5Format));
}